/*
 * @Author: fuqiming hb.fuqiming@aisino.com
 * @Date: 2024-03-09 17:17:11
 * @LastEditors: fuqiming hb.fuqiming@aisino.com
 * @LastEditTime: 2024-03-10 16:54:23
 * @Description: 
 */

import { ExtendPrototype } from "./global"

export namespace FQM_2 {
  // 首先, 装饰器都是函数

  // 类装饰器
  // 即直接拿到被类修饰器修饰的这个类(作为参数), 等价于直接调用这个函数: ClassDecocator(FQM)
  const ClassDecocator: ClassDecorator = function (target) {
    console.log('类装饰器不传参', target)
    target.prototype.fqm_ = function (): void {
      // 增加通用功能
      console.log('增加通用功能')
    }
  }

  // 只有类装饰器才能传参: 注意使用函数参数接收即可, 返回一个函数在用于接收这个类
  function ClassDecocator_2(param: string): ClassDecorator {
    console.log('类装饰器传参:', param)
    return (target: Function) => {
      console.log(target)
    }
  }

  // 属性装饰器
  // 即直接拿到这个属性装饰器的类和属性名
  // 注意, 此时只是拿到了这个类 并没有实例化
  const PropertyDecorator: PropertyDecorator = function (target, propertyKey) {
    console.log('属性装饰器', target, propertyKey)
  }

  // 传参
  const PropertyDecorator2 = function (value?: string): PropertyDecorator {
    return function (target, propertyKey) {
      console.log('属性装饰器2-传参', value ?? '', target, propertyKey)
    }
  }

  // 方法装饰器
  // 同上 descriptor 是描述这个的对象
  const MethodDecorator: MethodDecorator = function (target, propertyKey, descriptor) {
    console.log('方法装饰器', target, propertyKey, descriptor);
  }

  // 传参
  const MethodDecorator2 = function (value?: string): MethodDecorator {
    return function (target, propertyKey, descriptor) {
      console.log('方法装饰器2-传参', value ?? '', target, propertyKey, descriptor)
    }
  }

  // 参数装饰器
  // 同上, parameterIndex是参数序号
  const ParamDecorator: ParameterDecorator = function (target, propertyKey, parameterIndex) {
    console.log('参数装饰器', target, propertyKey, parameterIndex);
  }

  const ParamDecorator2 = function (value?: string): ParameterDecorator {
    return function (target, propertyKey, parameterIndex) {
      console.log('参数装饰器2-传参', value ?? '', target, propertyKey, parameterIndex)
    }
  }


  // 注意装饰器函数运行的顺序是由近到远，谁离被装饰的目标近谁就先运行

  @ClassDecocator_2('fqmyysjjd')
  @ClassDecocator
  export class FQM extends ExtendPrototype {
    @PropertyDecorator2('fqmyysjjddx')
    @PropertyDecorator
    private fqm: string = 'fqm'

    constructor() {
      super()
      this.fqm = 'fqmyysjjd'
    }

    @MethodDecorator2('fqmyytbd')
    @MethodDecorator
    fqmyysjjd() {
      return this.fqm
    }

    setFqm(@ParamDecorator2('fqmyybjjzw') @ParamDecorator fqm: string) {
      return this.fqm = fqm
    }
  }

  // test
  let fqm = new FQM_2.FQM()
  fqm.fqm_ && fqm.fqm_();


  // 访问器装饰器(方法装饰器)
  function logAccess(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const getter = descriptor.get;
    const setter = descriptor.set;

    descriptor.get = function () {
      console.log(`Getting value of ${propertyKey}.`);
      return getter?.call(this);
    };
    descriptor.set = function (value: any) {
      console.log(`Setting value of ${propertyKey} to ${value}.`);
      setter?.call(this, value);
    };
  }

  class MyClass {
    private _value: number = 0;

    // class 可以设置get, set对属性进行
    @logAccess
    get value(): number {
      return this._value;
    }

    set value(newValue: number) {
      this._value = newValue;
    }
  }

  // test
  const ex = new MyClass()
  console.log(ex.value);
  ex.value = 2
  console.log(ex.value);
}
